package com.yonyou.cyxdms.sysAuth.service.utill;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Map;
import java.util.Random;

/**
 * 生成随机图片，用来作为验证码
 */
public class Verification {

    // 生成的图片的宽度
    public static final int WIDTH = 160;
    // 生成的图片的高度
    public static final int HEIGHT = 34;

    /**
     * 生成验证码
     *
     * @return void
     * @author renwd
     * @since 2019/3/5
     */
    public static Map<String, Object> generate() {
        // 1.在内存中创建一张图片
        BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        // 2.得到图片
        Graphics g = bi.getGraphics();
        // 3.设置图片的背影色
        setBackGround(g);
        // 4.设置图片的边框
        setBorder(g);
        // 5.在图片上画干扰线
        drawRandomLine(g);
        drawRandomCircle(g);
        // 6.写在图片上随机数，生成数字和字母组合的验证码图片
        String random = drawRandomNum((Graphics2D) g, "nl");
        // 7.返回map
        Map<String, Object> map = MapUtils.newHashMap();
        map.put("random", random);
        map.put("bufferedImage", bi);
        return map;
    }

    /**
     * 转为base64
     *
     * @param bi
     * @return java.lang.String
     * @author renwd
     * @since 2019/3/6
     */
    public static String getStream(BufferedImage bi) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(bi, "jpg", outputStream);
        return Base64.getEncoder().encodeToString(outputStream.toByteArray());
    }

    /**
     * 设置图片的背景色
     *
     * @param g
     * @author renwd
     * @since 2019/3/5
     */
    private static void setBackGround(Graphics g) {
        // 设置颜色
        g.setColor(Color.WHITE);
        // 填充区域
        g.fillRect(0, 0, WIDTH, HEIGHT);
    }

    /**
     * 设置图片的边框
     *
     * @param g
     * @author renwd
     * @since 2019/3/5
     */
    private static void setBorder(Graphics g) {
        // 设置边框颜色
        g.setColor(Color.BLACK);
        // 边框区域
        g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
    }

    /**
     * 在图片上画随机线条
     *
     * @param g
     * @author renwd
     * @since 2019/3/5
     */
    private static void drawRandomLine(Graphics g) {
        for (int i = 0; i < 15; i++) {
            // 设置颜色
            g.setColor(Color.GREEN);
            int x1 = new Random().nextInt(WIDTH);
            int y1 = new Random().nextInt(HEIGHT);
            int x2 = new Random().nextInt(WIDTH);
            int y2 = new Random().nextInt(HEIGHT);
            int angle = new Random().nextInt(360);
            g.drawArc(x1, y1, x2, y2, 30, angle);
        }
    }

    //画点
    private static void drawRandomCircle(Graphics g) {
        for (int i = 0; i < 100; i++) {
            g.setColor(new Color(0x123456));
            int x = new Random().nextInt(WIDTH);
            int y = new Random().nextInt(HEIGHT);
            g.fillOval(x, y, 2, 2);
        }
    }


    /**
     * 画随机字符
     *
     * @param g
     * @param createTypeFlag
     * @return String... createTypeFlag是可变参数，
     * Java1.5增加了新特性：可变参数：适用于参数个数不确定，类型确定的情况
     * ，java把可变参数当做数组处理。注意：可变参数必须位于最后一项
     */
    private static String drawRandomNum(Graphics2D g, String... createTypeFlag) {
        // 设置颜色
        g.setColor(Color.RED);
        // 设置字体
        g.setFont(new Font("", Font.BOLD, 20));
        // 数字和字母的组合
        String baseNumLetter = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZ";
        // createTypeFlag[0]==null表示没有传递参数
        if (createTypeFlag.length > 0 && null != createTypeFlag[0]) {
            if ("nl".equals(createTypeFlag[0])) {
                // 截取数字和字母
                return createRandomChar(g, baseNumLetter);
            }
        }

        return "";
    }

    /**
     * 创建随机字符
     *
     * @param g
     * @param baseChar
     * @return 随机字符
     */
    private static String createRandomChar(Graphics2D g, String baseChar) {
        StringBuffer sb = new StringBuffer();
        int x = 5;
        String ch = "";
        // 控制字数
        for (int i = 0; i < 4; i++) {
            // 设置字体旋转角度
            int degree = new Random().nextInt() % 30;
            ch = baseChar.charAt(new Random().nextInt(baseChar.length())) + "";
            sb.append(ch);
            // 正向角度
            g.rotate(degree * Math.PI / 180, x, 20);
            g.drawString(ch, x, 20);
            // 反向角度
            g.rotate(-degree * Math.PI / 180, x, 20);
            x += 30;
        }
        return sb.toString();
    }
}